package icu.cqcai.xinsi.controller;

import icu.cqcai.xinsi.domain.dto.UserLoginRequest;
import icu.cqcai.xinsi.domain.dto.UserLoginResponse;
import icu.cqcai.xinsi.domain.dto.UserRegisterRequest;
import icu.cqcai.xinsi.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.util.HashMap;
import java.util.Map;

/**
 * 用户控制器 - 用户认证与管理系统
 * 
 * 主要功能：
 * 1. 用户注册 - 新用户账号创建和验证
 * 2. 用户登录 - 身份认证和JWT令牌生成
 * 3. 用户登出 - 会话终止和令牌清理
 * 4. 用户信息管理 - 个人资料查询和维护
 * 5. 数据唯一性验证 - 用户名和邮箱重复检查
 * 6. 令牌验证 - JWT令牌有效性检查
 * 
 * 安全特性：
 * - JWT令牌认证机制
 * - HttpOnly Cookie防XSS攻击
 * - 跨域请求支持
 * - 输入参数验证和清理
 * - 异常处理和错误日志记录
 * 
 * 认证流程：
 * 注册 → 登录 → 令牌生成 → 访问控制 → 登出
 * 
 * 技术特点：
 * - RESTful API设计
 * - 多种令牌获取方式（Header、Cookie）
 * - 完整的错误处理机制
 * - 详细的操作日志记录
 * - 响应式的状态管理
 * 
 * @author xinsi团队
 * @version 1.0
 * @since 2024
 */
@RestController
@RequestMapping("/api/users")
@CrossOrigin(origins = "*", allowedHeaders = "*") // 允许跨域访问 - 支持前后端分离架构
public class UserController {
    
    /**
     * 日志记录器 - 用于记录用户控制器的操作日志
     */
    private static final Logger logger = LoggerFactory.getLogger(UserController.class);
    
    /**
     * 用户服务层 - 核心业务逻辑处理
     * 负责用户认证、数据验证、令牌管理等业务操作
     */
    @Autowired
    private UserService userService;
    
    /**
     * 用户注册 - 新用户账号创建接口
     * 
     * 注册流程：
     * 1. 接收用户注册信息
     * 2. 验证用户名和邮箱唯一性
     * 3. 密码加密处理
     * 4. 用户数据存储
     * 5. 返回注册结果
     * 
     * 验证规则：
     * - 用户名唯一性检查
     * - 邮箱格式和唯一性验证
     * - 密码强度要求
     * - 必填字段完整性检查
     * 
     * 安全措施：
     * - 密码加密存储
     * - 输入数据清理
     * - SQL注入防护
     * - 异常信息脱敏
     * 
     * @param registerRequest 用户注册请求对象
     *                       - username: 用户名（必填，唯一）
     *                       - email: 邮箱地址（必填，唯一）
     *                       - password: 密码（必填，将被加密）
     *                       - confirmPassword: 确认密码（必填，需与密码一致）
     * @return Map<String, Object> 注册结果响应
     *         - success: 布尔值，表示注册是否成功
     *         - message: 字符串，详细的结果信息
     */
    @PostMapping("/register")
    public Map<String, Object> register(@RequestBody UserRegisterRequest registerRequest) {
        logger.info("=== 开始处理用户注册请求 ===");
        logger.info("注册请求 - 用户名: {}, 邮箱: {}", registerRequest.getUsername(), registerRequest.getEmail());
        
        Map<String, Object> response = new HashMap<>();
        
        try {
            // ========== 调用业务层处理注册逻辑 ==========
            String result = userService.register(registerRequest);
            
            // ========== 根据业务层返回结果构建响应 ==========
            if ("注册成功".equals(result)) {
                response.put("success", true);
                response.put("message", result);
                logger.info("用户注册成功: {}", registerRequest.getUsername());
            } else {
                // 注册失败，返回具体错误信息
                response.put("success", false);
                response.put("message", result);
                logger.warn("用户注册失败: {}, 原因: {}", registerRequest.getUsername(), result);
            }
            
        } catch (Exception e) {
            // ========== 异常处理 ==========
            logger.error("注册过程发生异常，用户名: {}: ", registerRequest.getUsername(), e);
            
            response.put("success", false);
            response.put("message", "注册过程发生错误，请稍后重试");
        } finally {
            logger.info("=== 用户注册请求处理完成 ===");
        }
        
        return response;
    }
    
    /**
     * 用户登录 - 身份认证和会话建立接口
     * 
     * 登录流程：
     * 1. 接收用户登录凭证
     * 2. 验证用户名和密码
     * 3. 生成JWT访问令牌
     * 4. 设置HttpOnly Cookie
     * 5. 返回登录结果和用户信息
     * 
     * 认证机制：
     * - 密码哈希验证
     * - JWT令牌生成
     * - 会话状态管理
     * - 令牌过期控制
     * 
     * 安全特性：
     * - HttpOnly Cookie防止XSS攻击
     * - 令牌有效期控制（24小时）
     * - 路径作用域限制
     * - 生产环境HTTPS支持
     * 
     * Cookie设置：
     * - HttpOnly: 防止JavaScript访问
     * - Path: 根路径，全站可用
     * - MaxAge: 24小时自动过期
     * - Secure: 生产环境HTTPS传输
     * 
     * @param loginRequest 用户登录请求对象
     *                    - username: 用户名或邮箱（必填）
     *                    - password: 密码（必填）
     * @param response HTTP响应对象，用于设置Cookie
     * @return UserLoginResponse 登录结果响应对象
     *         - success: 登录是否成功
     *         - token: JWT访问令牌
     *         - username: 用户名
     *         - message: 结果信息
     */
    @PostMapping("/login")
    public UserLoginResponse login(@RequestBody UserLoginRequest loginRequest, HttpServletResponse response) {
        logger.info("=== 开始处理用户登录请求 ===");
        logger.info("登录请求 - 用户名: {}", loginRequest.getUsername());
        
        try {
            // ========== 调用业务层执行登录验证 ==========
            UserLoginResponse loginResponse = userService.login(loginRequest);
            
            if (loginResponse.isSuccess()) {
                logger.info("用户登录成功: {}", loginRequest.getUsername());
                
                // ========== 设置JWT令牌为HttpOnly Cookie ==========
                Cookie tokenCookie = new Cookie("token", loginResponse.getToken());
                tokenCookie.setHttpOnly(true);  // 防止XSS攻击 - JavaScript无法访问
                tokenCookie.setPath("/");       // 设置为根路径，整个网站都可以访问
                tokenCookie.setMaxAge(24 * 60 * 60); // 24小时过期
                // 在生产环境中应该设置为true，确保只在HTTPS连接中发送
                // tokenCookie.setSecure(true);  // 只在HTTPS连接中发送
                
                response.addCookie(tokenCookie);
                logger.debug("JWT token已设置为HttpOnly cookie，有效期24小时");
            } else {
                logger.warn("用户登录失败: {}, 原因: {}", loginRequest.getUsername(), loginResponse.getMessage());
            }
            
            return loginResponse;
            
        } catch (Exception e) {
            // ========== 异常处理 ==========
            logger.error("登录过程发生异常，用户名: {}: ", loginRequest.getUsername(), e);
            
            return UserLoginResponse.failure("登录过程发生错误，请稍后重试");
        } finally {
            logger.info("=== 用户登录请求处理完成 ===");
        }
    }
    
    /**
     * 检查用户名是否可用 - 实时唯一性验证接口
     * 
     * 功能说明：
     * 1. 实时检查用户名是否已被占用
     * 2. 支持注册表单的实时验证
     * 3. 提供友好的用户体验
     * 4. 防止重复提交无效数据
     * 
     * 验证逻辑：
     * - 空值检查和字符串清理
     * - 数据库唯一性查询
     * - 结果状态和消息返回
     * - 异常情况的容错处理
     * 
     * 使用场景：
     * - 注册表单实时验证
     * - 用户名输入框失焦检查
     * - 批量用户名可用性检查
     * 
     * @param username 待检查的用户名
     * @return Map<String, Object> 检查结果
     *         - available: 布尔值，用户名是否可用
     *         - message: 字符串，检查结果说明
     */
    @GetMapping("/check-username")
    public Map<String, Object> checkUsername(@RequestParam String username) {
        logger.info("=== 检查用户名是否可用: {} ===", username);
        
        Map<String, Object> response = new HashMap<>();
        
        try {
            // ========== 输入参数验证 ==========
            if (username == null || username.trim().isEmpty()) {
                logger.warn("用户名检查失败：用户名为空");
                response.put("available", false);
                response.put("message", "用户名不能为空");
                return response;
            }
            
            // ========== 字符串清理和唯一性检查 ==========
            String trimmedUsername = username.trim();
            boolean exists = userService.isUsernameExists(trimmedUsername);
            
            // ========== 构建检查结果 ==========
            response.put("available", !exists);
            response.put("message", exists ? "用户名已存在" : "用户名可用");
            
            logger.debug("用户名 {} 检查结果: {}", trimmedUsername, exists ? "已存在" : "可用");
            
        } catch (Exception e) {
            // ========== 异常处理 ==========
            logger.error("检查用户名过程发生异常，用户名: {}: ", username, e);
            
            response.put("available", false);
            response.put("message", "检查用户名时发生错误");
        }
        
        return response;
    }
    
    /**
     * 检查邮箱是否可用 - 邮箱唯一性验证接口
     * 
     * 功能说明：
     * 1. 实时检查邮箱是否已被注册
     * 2. 支持邮箱格式的基础验证
     * 3. 防止重复邮箱注册
     * 4. 提供即时反馈机制
     * 
     * 验证流程：
     * - 邮箱格式初步检查
     * - 数据库重复性查询
     * - 可用性状态返回
     * - 错误情况处理
     * 
     * 业务规则：
     * - 一个邮箱只能注册一个账号
     * - 支持邮箱格式的基础验证
     * - 大小写不敏感处理
     * - 前后空格自动清理
     * 
     * @param email 待检查的邮箱地址
     * @return Map<String, Object> 检查结果
     *         - available: 布尔值，邮箱是否可用
     *         - message: 字符串，检查结果说明
     */
    @GetMapping("/check-email")
    public Map<String, Object> checkEmail(@RequestParam String email) {
        logger.info("=== 检查邮箱是否可用: {} ===", email);
        
        Map<String, Object> response = new HashMap<>();
        
        try {
            // ========== 输入参数验证 ==========
            if (email == null || email.trim().isEmpty()) {
                logger.warn("邮箱检查失败：邮箱为空");
                response.put("available", false);
                response.put("message", "邮箱不能为空");
                return response;
            }
            
            // ========== 邮箱清理和唯一性检查 ==========
            String trimmedEmail = email.trim();
            boolean exists = userService.isEmailExists(trimmedEmail);
            
            // ========== 构建检查结果 ==========
            response.put("available", !exists);
            response.put("message", exists ? "邮箱已被使用" : "邮箱可用");
            
            logger.debug("邮箱 {} 检查结果: {}", trimmedEmail, exists ? "已被使用" : "可用");
            
        } catch (Exception e) {
            // ========== 异常处理 ==========
            logger.error("检查邮箱过程发生异常，邮箱: {}: ", email, e);
            
            response.put("available", false);
            response.put("message", "检查邮箱时发生错误");
        }
        
        return response;
    }
    
    /**
     * 检查JWT令牌是否有效 - 令牌验证和用户状态检查接口
     * 
     * 功能说明：
     * 1. 验证JWT令牌的有效性和完整性
     * 2. 支持多种令牌获取方式
     * 3. 返回令牌关联的用户信息
     * 4. 提供会话状态检查
     * 
     * 令牌获取优先级：
     * 1. Authorization Header (Bearer Token)
     * 2. HttpOnly Cookie
     * 3. 其他自定义方式
     * 
     * 验证内容：
     * - 令牌格式正确性
     * - 令牌签名验证
     * - 令牌过期时间检查
     * - 用户状态有效性
     * 
     * 安全考虑：
     * - 防止令牌伪造
     * - 过期令牌自动失效
     * - 用户状态实时检查
     * - 异常情况安全处理
     * 
     * @param authorization Authorization请求头，格式为"Bearer {token}"
     * @param request HTTP请求对象，用于读取Cookie中的令牌
     * @return Map<String, Object> 验证结果
     *         - valid: 布尔值，令牌是否有效
     *         - username: 字符串，令牌关联的用户名
     *         - message: 字符串，验证结果说明
     */
    @GetMapping("/check")
    public Map<String, Object> checkToken(@RequestHeader(value = "Authorization", required = false) String authorization,
                                        HttpServletRequest request) {
        logger.info("=== 检查JWT token有效性 ===");
        
        Map<String, Object> response = new HashMap<>();
        
        try {
            String token = null;
            
            // ========== 令牌获取 - 多种方式支持 ==========
            // 优先从Authorization header获取token
            if (authorization != null && authorization.startsWith("Bearer ")) {
                token = authorization.substring(7);
                logger.debug("从Authorization header获取token");
            } else {
                // 从cookie获取token - 备用方案
                Cookie[] cookies = request.getCookies();
                if (cookies != null) {
                    for (Cookie cookie : cookies) {
                        if ("token".equals(cookie.getName())) {
                            token = cookie.getValue();
                            logger.debug("从cookie获取token");
                            break;
                        }
                    }
                }
            }
            
            // ========== 令牌存在性检查 ==========
            if (token == null || token.trim().isEmpty()) {
                logger.warn("Token检查失败：未找到有效token");
                response.put("valid", false);
                response.put("message", "Missing token");
                return response;
            }
            
            // ========== 令牌有效性验证 ==========
            boolean isValid = userService.validateToken(token);
            
            if (isValid) {
                // 令牌有效，获取用户信息
                String username = userService.getUsernameFromToken(token);
                response.put("valid", true);
                response.put("username", username);
                response.put("message", "Token is valid");
                logger.info("Token验证成功，用户: {}", username);
            } else {
                // 令牌无效或已过期
                response.put("valid", false);
                response.put("message", "Invalid or expired token");
                logger.warn("Token验证失败：令牌无效或已过期");
            }
            
        } catch (Exception e) {
            // ========== 异常处理 ==========
            logger.error("验证token过程发生异常: ", e);
            
            response.put("valid", false);
            response.put("message", "Token validation error");
        }
        
        return response;
    }
    
    /**
     * 获取用户信息 - 需要令牌验证的用户资料接口
     * 
     * 功能说明：
     * 1. 获取当前登录用户的详细信息
     * 2. 验证访问权限和令牌有效性
     * 3. 返回用户的个人资料数据
     * 4. 支持用户信息的动态更新
     * 
     * 访问控制：
     * - 必须提供有效的JWT令牌
     * - 令牌必须通过签名验证
     * - 令牌不能过期
     * - 用户状态必须正常
     * 
     * 返回信息：
     * - 基础用户信息（用户名、邮箱等）
     * - 用户权限和角色
     * - 账户状态信息
     * - 其他个人资料数据
     * 
     * 安全措施：
     * - 敏感信息过滤
     * - 权限级别检查
     * - 数据脱敏处理
     * - 访问日志记录
     * 
     * @param authorization Authorization请求头，必须包含有效的Bearer令牌
     * @return Map<String, Object> 用户信息响应
     *         - success: 布尔值，请求是否成功
     *         - user: 对象，用户详细信息
     *         - message: 字符串，响应状态说明
     */
    @GetMapping("/profile")
    public Map<String, Object> getUserProfile(@RequestHeader(value = "Authorization", required = false) String authorization) {
        logger.info("=== 获取用户信息 ===");
        
        Map<String, Object> response = new HashMap<>();
        
        try {
            // ========== Authorization Header验证 ==========
            if (authorization == null || !authorization.startsWith("Bearer ")) {
                response.put("success", false);
                response.put("message", "Missing or invalid authorization header");
                return response;
            }
            
            // ========== 提取和验证JWT令牌 ==========
            String token = authorization.substring(7); // 移除 "Bearer " 前缀
            boolean isValid = userService.validateToken(token);
            
            if (isValid) {
                // ========== 获取用户信息 ==========
                String username = userService.getUsernameFromToken(token);
                
                // 构建用户信息响应
                Map<String, Object> userInfo = new HashMap<>();
                userInfo.put("username", username);
                // 可以在这里添加更多用户信息，如邮箱、角色等
                // userInfo.put("email", userService.getEmailByUsername(username));
                // userInfo.put("role", userService.getUserRole(username));
                
                response.put("success", true);
                response.put("user", userInfo);
                response.put("message", "User profile retrieved successfully");
                
                logger.info("成功获取用户信息: {}", username);
            } else {
                // ========== 令牌验证失败 ==========
                response.put("success", false);
                response.put("message", "Invalid or expired token");
                logger.warn("Token验证失败：令牌无效或已过期");
            }
            
        } catch (Exception e) {
            // ========== 异常处理 ==========
            logger.error("获取用户信息过程发生异常: ", e);
            
            response.put("success", false);
            response.put("message", "Error retrieving user profile");
        }
        
        return response;
    }
    
    /**
     * 用户登出 - 会话终止和令牌清理接口
     * 
     * 功能说明：
     * 1. 终止用户的当前会话
     * 2. 清理客户端存储的令牌
     * 3. 失效相关的认证信息
     * 4. 提供安全的退出机制
     * 
     * 登出流程：
     * 1. 接收登出请求
     * 2. 清除HttpOnly Cookie
     * 3. 失效服务端会话（如果有）
     * 4. 返回登出结果
     * 
     * 安全考虑：
     * - 立即清除客户端令牌
     * - 防止令牌被恶意使用
     * - 确保会话完全终止
     * - 记录登出操作日志
     * 
     * Cookie清理：
     * - 设置Cookie值为空
     * - 立即过期（MaxAge=0）
     * - 保持相同的路径和域
     * - 维持HttpOnly属性
     * 
     * @param response HTTP响应对象，用于清除Cookie
     * @return Map<String, Object> 登出结果
     *         - success: 布尔值，登出是否成功
     *         - message: 字符串，登出结果说明
     */
    @PostMapping("/logout")
    public Map<String, Object> logout(HttpServletResponse response) {
        logger.info("=== 用户登出 ===");
        
        Map<String, Object> result = new HashMap<>();
        
        try {
            // ========== 清除令牌Cookie ==========
            Cookie tokenCookie = new Cookie("token", "");
            tokenCookie.setHttpOnly(true);  // 保持HttpOnly属性
            tokenCookie.setPath("/");       // 保持相同路径
            tokenCookie.setMaxAge(0);       // 立即过期，浏览器会删除此Cookie
            
            response.addCookie(tokenCookie);
            
            // ========== 构建成功响应 ==========
            result.put("success", true);
            result.put("message", "登出成功");
            
            logger.info("用户登出成功，cookie已清除");
            
        } catch (Exception e) {
            // ========== 异常处理 ==========
            logger.error("登出过程发生异常: ", e);
            
            result.put("success", false);
            result.put("message", "登出过程发生错误");
        }
        
        return result;
    }
} 